<?php

# -- DÉBUT NOTE DE LICENCE -------------------------------------
#
# Ce fichier fait partie de Clicpage.
#
# Copyright (c) 2010 Francois (www.clicpage.net)
# Distribué selon les termes de la licence GPL version 2.0.
# Consultez le fichier LICENCE ou
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
#
# -- FIN NOTE DE LICENCE ---------------------------------------

/**
@ingroup CP_CORE
@nosubgrouping
@brief Authentification

cpAuth gère l'authentification d'un utilisateur à la partie publique et/ou
à l'interface d'administration du site.
*/
class cpAuth
{


	
	
	
	protected $core;								///< <b>cpCore</b>	Instance de cpCore
	
	public $utilisateur;							///< <b>cpUtilisateur</b>	Utilisateur actuel
	protected $permissions;							///< <b>array</b>			Permissions de l'utilisateur actuel
	
	protected $permissionsDisponibles = array();	///< <b>array</b>	Permissions qu'il est possible d'avoir
	
	
	
	

	/// @name Initialisation
	//@{
	
	
	/**
	Initialise une instance de cpAuth.
	
	@param	core		<b>cpCore</b>		Référence à cpCore
	*/
	public function __construct($core)
	{
		$this->core =& $core;
		$this->core->session->start();

		$this->permissionsDefaut();
	}
	
	
	/** @ignore */
	public function permissionsDefaut()
	{
		$this->permissionsDisponibles = array(
			'public_commentaires' => array(__('Publier des commentaires lorsque l\'accès à ceux-ci est restreint.'), __('Vous n\'êtes pas autorisé à publier des commentaires sur cette page.'), array()),
			'administrer' => array(__('Accéder à l\'interface d\'administration.'), __('Vous n\'êtes pas autorisé à accéder à l\'interface d\'administration.'), array()),
			'pages' => array(__('Créer et gérer ses propres pages.'), __('Vous ne pouvez pas créer ou gérer les pages du site.'), array('administrer')),
			'toutesPages' => array(__('Agir sur des pages dont il n\'est pas l\'auteur.'), __('Vous ne pouvez pas modifier des pages dont vous n\'êtes pas l\'auteur.'), array('administrer', 'pages')),
			'publierPage' => array(__('Publier des pages.'), __('Vous ne pouvez pas publier des pages.'), array('administrer', 'pages')),
			'supprimerPage' => array(__('Supprimer des pages dont il n\'est pas l\'auteur.'), __('Vous ne pouvez pas supprimer les pages dont vous n\'êtes pas l\'auteur.'), array('administrer', 'toutesPages')),
			'creerCategorie' => array(__('Créer de nouveaux dossiers.'), __('Vous ne pouvez pas créer de nouveaux dossiers.'), array('administrer', 'pages')),
			'supprimerCategorie' => array(__('Supprimer des dossiers.'), __('Vous ne pouvez pas supprimer de dossiers.'), array('administrer', 'pages', 'supprimerPage')),
			'medias' => array(__('Transférer et gérer ses propres médias.'), __('Vous ne pouvez pas gérer les médias.'), array('administrer')),
			'tousMedias' => array(__('Agir sur des médias dont il n\'est pas l\'auteur.'), __('Vous ne pouvez pas gérer les médias dont vous n\'êtes pas l\'auteur.'), array('administrer', 'medias')),
			'supprimerMedia' => array(__('Supprimer des médias dont il n\'est pas l\'auteur.'), __('Vous ne pouvez pas supprimer les médias dont vous n\'êtes pas l\'auteur.'), array('administrer', 'tousMedias')),
			'commentaires' => array(__('Modérer les commentaires.'), __('Vous ne pouvez pas modérer les commentaires.'), array('administrer')),
			'reglages' => array(__('Modifier les réglages du site.'), __('Vous ne pouvez pas modifier les réglages du site.'), array('administrer')),
			'apparence' => array(__('Modifier l\'apparence du site.'), __('Vous ne pouvez pas modifier l\'apparence du site.'), array('administrer', 'reglages')),
			'gadgets' => array(__('Gérer les gadgets.'), __('Vous ne pouvez pas gérer les gadgets.'), array('administrer')),
			'utilisateurs' => array(__('Gérer les utilisateurs.'), __('Vous ne pouvez pas gérer les utilisateurs.'), array('administrer'))
		);
	}
	//@}
	
	
	
	
	
	/// @name Connexion / déconnexion
	//@{
	
	
	/**
	Vérifie la validité d'un nom d'utilisateur et d'un mot de passe, et,
	si les données sont valides, crée une session d'identification.
	
	@param	utilisateur_login	<b>string</b>	Nom d'utilisateur
	@param	mot_de_passe		<b>string</b>	Mot de passe
	@param	se_souvenir			<b>bool</b>		Indique si un cookie doit être créé pour se souvenir de l'utilisateur
	
	@return	<b>boolean</b>	indique si les informations de connexion sont valides
	*/
	public function connecterUtilisateur($utilisateur_login, $mot_de_passe, $se_souvenir=false)
	{
	
		# Vérifier l'utilisateur et son mot de passe
		$strReq = 'SELECT utilisateur_id,utilisateur_login,'.
			'utilisateur_mot_de_passe, utilisateur_cle '.
			'FROM '.$this->core->prefix.'utilisateurs '.
			"WHERE utilisateur_login = '".$this->core->con->escape($utilisateur_login)."' ".
			'AND utilisateur_statut = '.CP_UTILISATEUR_ACTIF;
			
		$rs = $this->core->con->select($strReq);

		if($rs->isEmpty) {
			return false;
		}

		if($mot_de_passe != '')
		{
			if(crypt::hmac(CP_MASTER_KEY,$mot_de_passe) != $rs->utilisateur_mot_de_passe) {
				sleep(rand(2,5));
				return false;
			}
		}
		else {
			return false;
		}

		$_SESSION['utilisateur_id'] = (integer) $rs->utilisateur_id;
		$this->core->genererNonce('ajax');

		# Se souvenir de l'utilisateur?
		if($se_souvenir) {
			$this->genererCookieSeSouvenir((integer) $rs->utilisateur_id);
		} else {
			$cle = unserialize($rs->utilisateur_cle);
			unset($cle['se_souvenir']);
			$cur = $this->core->con->openCursor($this->core->prefix.'utilisateurs');
			$cur->utilisateur_cle = serialize($cle);
			$cur->update('WHERE utilisateur_id = '.(integer) $rs->utilisateur_id);
			setcookie(CP_NOM_SESSION.'_se_souvenir_cle',false,-600);
			setcookie(CP_NOM_SESSION.'_se_souvenir_uid',false,-600);
		}
		
		return true;
	
	}
	
	
	/** @ignore */
	public function genererCookieSeSouvenir($utilisateur_id)
	{
		
		$rs = $this->core->con->select(
			'SELECT utilisateur_cle FROM '.$this->core->prefix.'utilisateurs '.
			'WHERE utilisateur_id = '.(integer) $utilisateur_id
		);

		$cle_md5 = md5(uniqid());
			
		$cle = unserialize($rs->utilisateur_cle);

		$cle['se_souvenir'] = array(
			'browserUID'		=> http::browserUID(CP_MASTER_KEY),
			'cle'				=> crypt::hmac(CP_MASTER_KEY, $cle_md5) 
		);
			
		$cur = $this->core->con->openCursor($this->core->prefix.'utilisateurs');
		$cur->utilisateur_cle = serialize($cle);
		$cur->update('WHERE utilisateur_id = '.(integer) $utilisateur_id);
		
		setcookie(CP_NOM_SESSION.'_se_souvenir_cle', $cle_md5, time()+86400*30, '/');
		setcookie(CP_NOM_SESSION.'_se_souvenir_uid', $utilisateur_id, time()+86400*30, '/');
		
	}
	
	
	/** @ignore */
	public function detruireCookieSeSouvenir()
	{
		if($this->estConnecte())
		{	
			$cle = $this->utilisateur->utilisateur_cle;
			unset($cle['se_souvenir']);
			$cur = $this->core->con->openCursor($this->core->prefix.'utilisateurs');
			$cur->utilisateur_cle = serialize($cle);
			$cur->update('WHERE utilisateur_id = '.(integer) $this->getUtilisateurID());
		}
	}
	
	
	/**
	Déconnecte l'utilisateur.
	*/
	public function deconnecterUtilisateur()
	{
		$this->detruireCookieSeSouvenir();		
		$this->core->session->destroy();
		if (isset($_COOKIE[CP_NOM_SESSION])) {
			unset($_COOKIE[CP_NOM_SESSION]);
			unset($_COOKIE[CP_NOM_SESSION.'_se_souvenir_cle']);
			unset($_COOKIE[CP_NOM_SESSION.'_se_souvenir_uid']);
			setcookie(CP_NOM_SESSION,false,-600);
			setcookie(CP_NOM_SESSION.'_se_souvenir_cle',false,-600);
			setcookie(CP_NOM_SESSION.'_se_souvenir_uid',false,-600);
		}
	}
	
	//@}
	
	
	
	
	
	/// @name Vérification de la connexion
	//@{
	
	
	/**
	Vérifie la validité d'une session d'identification.
	
	@return	<b>boolean</b>
	*/
	public function verifierSession()
	{
		if($_SESSION['sess_browser_uid'] != http::browserUID(CP_MASTER_KEY)) {
			return false;
		}
	
		return true;
	}
	
	
	/**
	Vérifie si un utilisateur est connecté, et si sa session
	d'identification est valide.
	
	Conserve une instance de cpUtilisateur pour l'utilisateur
	actuel dans la propriété <var>$utilisateur</var>
	
	@return	<b>boolean</b>
	*/
	public function verifierUtilisateur()
	{

		unset($this->utilisateur);

		if(empty($_SESSION['utilisateur_id']) || !$this->verifierSession()) {
			
			# L'utilisateur n'est pas connecté... vérifions s'il possède un cookie «se souvenir de moi»:
			if(isset($_COOKIE[CP_NOM_SESSION.'_se_souvenir_cle']) && isset($_COOKIE[CP_NOM_SESSION.'_se_souvenir_uid']))
			{
				
				# On cherche l'utilisateur dans la base de données
				$rs = $this->core->con->select(
					'SELECT utilisateur_id, utilisateur_cle FROM '.$this->core->prefix.'utilisateurs '.
					'WHERE utilisateur_id = '.(integer) $_COOKIE[CP_NOM_SESSION.'_se_souvenir_uid']
				);
				
				# Est-ce qu'il y a une clé?
				$cle = unserialize($rs->utilisateur_cle);
				if(	isset($cle['se_souvenir']) &&
					$cle['se_souvenir']['cle'] == crypt::hmac(CP_MASTER_KEY, $_COOKIE[CP_NOM_SESSION.'_se_souvenir_cle']) &&
					$cle['se_souvenir']['browserUID'] == http::browserUID(CP_MASTER_KEY))
				{
					$_SESSION['utilisateur_id'] = (integer) $rs->utilisateur_id;
					$_SESSION['sess_browser_uid'] = http::browserUID(CP_MASTER_KEY);
					$this->core->genererNonce('ajax');
					$this->genererCookieSeSouvenir($rs->utilisateur_id);
				}
				
			}
			else 
			{
				return false;
			}
			
		}
		
		$utilisateur = $this->core->site->getUtilisateurs(array(
			'utilisateur_id' => (integer) $_SESSION['utilisateur_id'],
			'utilisateur_statut' => CP_UTILISATEUR_ACTIF
		), CP_GET_STATIC);
	
		
		if($utilisateur->isEmpty()) {
			return false;
		}
		
		$this->utilisateur = $utilisateur;
		$this->chargerPermissions();
		
		return true;
	
	}
	
	
	/**
	Vérifie si l'utilisateur est connecté.
	
	@return	<b>boolean</b>
	*/
	public function estConnecte()
	{
		if(is_object($this->utilisateur)) {
			return true;
		}
		return false;
	}
	//@}
	
	
	
	
	
	/// @name Informations sur l'utilisateur connecté
	//@{
	
	
	/**
	Retourne l'identifiant de l'utilisateur présentement connecté.
	
	@return	<b>integer</b>	Identifiant de l'utilisateur
	*/
	public function getUtilisateurID()
	{
		if(!$this->estConnecte()) {
			return NULL;
		}

		return $this->utilisateur->utilisateur_id;
	}
	
	
	/**
	Indique si l'utilisateur présentement connecté est
	un superadmin.
	
	@return	<b>boolean</b>
	*/
	public function estSuperadmin()
	{
		if(!$this->estConnecte()) {
			return false;
		}
		
		return $this->utilisateur->estSuperadmin();
	}
	//@}





	/// @name Permissions de l'utilisateur connecté
	//@{
	
	
	/**
	Vérifie si l'utilisateur connecté a la permission
	<var>permission</var>.
	
	@param	permission		<b>string</b>	Nom de la permission à vérifier
	@param	throw			<b>boolean</b>	Envoyer cpErreur si l'utilisateur n'a pas la permission
	
	@return	<b>boolean</b>
	*/
	public function verifierPermission($permission, $throw = false)
	{

		# Pas connecté = pas de permissions
		if(!$this->estConnecte()) {
			return false;
		}

		# Un utilisateur a tous les droits
		if($this->estSuperadmin()) {
			return true;
		}
		
		if(empty($this->permissions[$permission]) || $permission == 'superadmin') {
			if(!empty($throw)) {
				if(empty($this->permissionsDisponibles[$permission])) {
					$message = __('Action non autorisée');
				} else {
					$message = $this->permissionsDisponibles[$permission][1];
				}
				throw new cpErreur($message, $permission, 201);
			}
			return false;
		}
		
		return true;
		
	}
	
	
	/**
	Recherche les permissions de l'utilisateur actuel
	dans la base de données.
	*/
	private function chargerPermissions()
	{

		$this->permissions = array();

		$rs = $this->core->site->getGroupesUtilisateurs(
			array('groupe_id' => $this->utilisateur->groupe_id),
			CP_GET_RS
		);
		
		if(!$rs->isEmpty()) {
			$this->permissions = unserialize($rs->groupe_permissions);
		}
		
	}
	//@}
	
	
	
	

	/// @name Permissions disponibles
	//@{
	
	
	/**
	Ajoute une permission à la liste des permissions disponibles.
	
	@param	permission_nom			<b>string</b>	Nom de la permission
	@param	permission_description	<b>string</b>	Courte description de la permission
	@param	permission_erreur		<b>string</b>	Message à afficher lorsqu'un utilisateur n'a pas la permission
	@param	permission_prealables	<b>array</b>	Nom des permissions préalables
	*/
	public function creerPermission($permission_nom, $permission_description, $permission_prealables)
	{
		$this->permissionsDisponibles[$permission_nom] = array($permission_description, $permission_erreur, $permission_prealables);
	}
	
	
	/**
	Retourne la liste des permissions disponibles.

	@return	<b>array</b>	Permissions disponibles
	*/
	public function getPermissionsDisponibles()
	{
		return $this->permissionsDisponibles;
	}
	//@}
	
	
}

?>